using System;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
using System.IO;
using System.Text;

namespace BizElements.Generator
{
	/// <summary>
	/// System entry point.
	/// </summary>
	public class AppMain
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args) 
		{            
            Control.CheckForIllegalCrossThreadCalls = false;
			AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleUnhandledException);
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			Application.EnableVisualStyles();			
			Application.DoEvents();

            Form mainFrm = CmdLineParser.GetIdeForm(args);
			Application.Run(mainFrm);
		}

		private static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs evtargs)
		{            
            StringBuilder errmsg = new StringBuilder();
            Exception e = evtargs.ExceptionObject as Exception;
            if (e == null)
            {
                errmsg.Append(Convert.ToString(evtargs.ExceptionObject));
            }
            else if (e is ReflectionTypeLoadException)
            {
                ReflectionTypeLoadException rtle = (ReflectionTypeLoadException)e;
                errmsg.AppendLine(rtle.Message);
                errmsg.AppendLine();
                foreach (Exception loaderException in rtle.LoaderExceptions)
                    errmsg.AppendLine(loaderException.Message);
            }
            else
            {
                errmsg.Append(e.Message);
                if (e.InnerException != null)
                {
                    errmsg.AppendLine();
                    errmsg.Append(e.InnerException.Message);
                }
            }

            ErrorFrm errfrm = new ErrorFrm() { ErrorMessage = errmsg.ToString() };
            errfrm.ShowDialog();
        }

        #region AsmDependenciesDirectory - required for .NET projects

        static string asmDependenciesDirectory;

        /// <summary>Gets or sets alternative assembly dependencies directory.</summary>
        public static string AsmDependenciesDirectory
        {
            get { return asmDependenciesDirectory ?? IoUtil.GetExecutableDirectory(); }
            set { asmDependenciesDirectory = value; }
        }

        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            // Contains("resources") --> handles issues when .NET 4.0 assemblies are loaded by template engine.
            if (AsmDependenciesDirectory == null || args.Name.Contains("resources"))
                return null;
            
            string shortName = args.Name.Split(',')[0];
            string asmPath = BuildAsmPath(AsmDependenciesDirectory, shortName);
            if (!File.Exists(asmPath))
                asmPath = BuildAsmPath(IoUtil.GetExecutableDirectory(), shortName);

            Assembly asm = Assembly.LoadFile(asmPath);
            return asm;
        }

        private static string BuildAsmPath(string dir, string shortName)
        {
            dir = TextUtil.EnsureSuffix(dir, @"\");
            string asmPath = dir + @"\" + shortName + ".dll";
            return asmPath;
        }

        #endregion
    }

    static class CmdLineParser
    {
        public static Form GetIdeForm(string[] cmdLineArgs)
        {
            Form ideForm;
            string projFile = ParseProjectFilePath(cmdLineArgs);
            if (!string.IsNullOrEmpty(projFile))
            {
                LoadIdeFormResults formWithProj = LoadProject(projFile);
                if (formWithProj.IdeForm != null)
                    ideForm = formWithProj.IdeForm;
                else
                    ideForm = new MainFrm(new MainFrm.OnLoadArgs() { ErrorMessage = formWithProj.Error });
            }
            else
            {
                ideForm = new MainFrm();
            }

            return ideForm;
        }

        private static string ParseProjectFilePath(string[] cmdLineArgs)
        {
            foreach (string arg in cmdLineArgs)
            {
                bool isSwitch = arg.StartsWith("/");
                if (!isSwitch)
                    return arg;
            }

            return null;
        }        

        private class LoadIdeFormResults
        {
            public Form IdeForm;
            public string Error;
        }

        private static LoadIdeFormResults LoadProject(string projFile)
        {
            LoadIdeFormResults nexgenProj = LoadNexGenProject(projFile);
            if (nexgenProj.IdeForm != null)
                return nexgenProj;

            return new LoadIdeFormResults() { Error = nexgenProj.Error };
        }

        private static LoadIdeFormResults LoadNexGenProject(string projFile)
        {            
            try
            {
                BizElementsSettings nexgenProj = BizElementsSettings.LoadFromFile(projFile);
                MainFrm.OnLoadArgs onLoadArgs = new MainFrm.OnLoadArgs() { Project = nexgenProj, ProjectFile = projFile };
                return new LoadIdeFormResults() { IdeForm = new MainFrm(onLoadArgs) };
            }
            catch (Exception e)
            {
                return new LoadIdeFormResults() { Error = e.ToString() };
            }
        }
    }
}
